﻿using System;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Threading;
using System.Xml;
using MSDNWebcast.Properties;
using MSDNWebcast.Service;

namespace MSDNWebcast.Models
{
    /// <summary>
    /// 课程信息初始化
    /// <remarks>
    /// 初始化包括三个部分：检查新课程，下载课程信息和加载课程信息
    /// </remarks>
    /// </summary>
    public class CourseInitializer : Downloader
    {
        #region Constructors

        /// <summary>
        /// 课程信息的初始化
        /// </summary>
        public CourseInitializer()
            : base(INFO_XML_BAK, Settings.Default.InfoXML)
        {
            this.PropertyChanged += CourseInitializerPropertyChanged;
        }

        #endregion

        #region Fields

        /// <summary>
        /// 下载中备份的课程信息文件路径
        /// </summary>
        private const string INFO_XML_BAK = "info.xml.bak";

        /// <summary>
        /// 课程信息文件路径
        /// </summary>
        public const string INFO_XML = "info.xml";

        /// <summary>
        /// 处理进度
        /// </summary>
        private int m_DownloadProcess;

        /// <summary>
        /// 进度信息
        /// </summary>
        private string m_ProcessInfo;

        #endregion

        #region Properties

        /// <summary>
        /// 初始化进度
        /// </summary>
        public int Process
        {
            get
            {
                return m_DownloadProcess;
            }
            set
            {
                if (m_DownloadProcess != value)
                {
                    m_DownloadProcess = value;
                    OnPropertyChanged("Process");
                }
            }
        }

        /// <summary>
        /// 进度处理信息
        /// </summary>
        public String ProcessInfo
        {
            get { return m_ProcessInfo; }
            set
            {
                if (m_ProcessInfo != value)
                {
                    m_ProcessInfo = value;
                    OnPropertyChanged("ProcessInfo");
                }
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// 处理进程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void Download(object sender, DoWorkEventArgs e)
        {
            var worker = (BackgroundWorker)sender;
            m_ProcessInfo = "检查新课程……";
            worker.ReportProgress(0);
            //等待动画结束
            Thread.Sleep(2700);
            if (HasNewInfoXml())
            {
                m_ProcessInfo = "下载数据中……";
                if (File.Exists(INFO_XML_BAK))
                    File.Delete(INFO_XML_BAK);
                worker.ReportProgress(0);

                base.Download(sender, e);

                if (File.Exists(INFO_XML_BAK))
                {
                    File.Copy(INFO_XML_BAK, INFO_XML, true);
                    File.Delete(INFO_XML_BAK);
                }
                m_DownloadProcess = 99;
            }
            else
            {
                m_DownloadProcess = 50;
            }
            m_ProcessInfo = "加载数据中……";
            worker.ReportProgress(0);

            ServiceFactory.Instance.GetService<CourseService>().LoadCourses();
        }

        /// <summary>
        /// 触发进度信息的更改
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            base.ProgressChanged(sender, e);
            OnPropertyChanged("ProcessInfo");
            OnPropertyChanged("Process");
        }

        /// <summary>
        /// 完成进程
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (!e.Cancelled && e.Error == null)
            {
                Process = 100;
                ProcessInfo = "加载完成";
            }
            base.ProcessCompleted(sender, e);
        }

        /// <summary>
        /// 使进度信息落后于实际文件下载的进度
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CourseInitializerPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "DownloadedSize" && FileSize > 0)
            {
                Process = Int32.Parse((DownloadedSize * 100 / (FileSize + 1)).ToString().TrimStart('.'));
            }
        }

        /// <summary>
        /// 检查新的info.xml信息
        /// </summary>
        /// <returns></returns>
        private static bool HasNewInfoXml()
        {
            if (!ValidateInfoXml())
                return true;

            var request = (HttpWebRequest) WebRequest.Create(Settings.Default.InfoXML);
            request.Proxy = WebRequest.DefaultWebProxy;
            request.Timeout = 10000;
            request.IfModifiedSince = new FileInfo(INFO_XML).LastWriteTime;
            request.Proxy.Credentials = CredentialCache.DefaultCredentials;

            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (Exception e)
            {
                var webException = e as WebException;
                if (webException != null && webException.Response != null)
                    response = (HttpWebResponse)webException.Response;
                else
                    throw;
            }
            return response.StatusCode != HttpStatusCode.NotModified;
        }

        /// <summary>
        /// 验证XML是否正确
        /// </summary>
        /// <returns></returns>
        public static bool ValidateInfoXml()
        {
            if (!File.Exists(INFO_XML))
                return false;
            var doc = new XmlDocument();
            try
            {
                doc.Load(INFO_XML);
            }
            catch
            {
                return false;
            }
            return true;
        }

        #endregion
    }
}
